/* * Copyright (c) 2007 by Damien Di Fede <ddf@compartmental.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package ddf.minim; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import org.tritonus.share.sampled.FloatSampleBuffer; final class MAudioSample extends Thread implements AudioStream { private SignalSplitter splitter; private EffectsChain effects; // sample stuff private AudioFormat format; private FloatSampleBuffer samples; private int[] marks; private int markAt; // line writing stuff private SourceDataLine line; private FloatSampleBuffer buffer; private boolean finished; MAudioSample(FloatSampleBuffer samps, SourceDataLine sdl, int bufferSize) { super(); format = sdl.getFormat(); splitter = new SignalSplitter(format, bufferSize); effects = new EffectsChain(); marks = new int[20]; for (int i = 0; i < marks.length; i++) marks[i] = -1; markAt = 0; samples = samps; line = sdl; buffer = new FloatSampleBuffer(format.getChannels(), bufferSize, format .getSampleRate()); bytes = new byte[bufferSize * 4]; finished = false; } public void trigger() { marks[markAt] = 0; markAt++; if (markAt == marks.length) markAt = 0; } private byte[] bytes; public void run() { try { line.open(format, bufferSize() * format.getFrameSize() * 4); } catch (LineUnavailableException e) { Minim.error("Error opening SourceDataLine: " + e.getMessage()); } line.start(); while (!finished) { // clear the buffer buffer.makeSilence(); // build our signal from all the marks for (int i = 0; i < marks.length; i++) { int begin = marks[i]; if (begin == -1) continue; //Minim.debug("Sample trigger in process at marks[" + i + "] = " + marks[i]); int j, k; for (j = begin, k = 0; j < samples.getSampleCount() && k < buffer.getSampleCount(); j++, k++) { if (type() == Minim.MONO) { buffer.getChannel(0)[k] += samples.getChannel(0)[j]; } else { buffer.getChannel(0)[k] += samples.getChannel(0)[j]; buffer.getChannel(1)[k] += samples.getChannel(1)[j]; } } if (j < samples.getSampleCount()) { marks[i] = j; } else { //Minim.debug("Sample trigger ended."); marks[i] = -1; } } // apply effects and broadcast samples to our listeners if (type() == Minim.MONO) { if (effects.hasEnabled()) { effects.process(buffer.getChannel(0)); } splitter.samples(buffer.getChannel(0)); } else { if (effects.hasEnabled()) { effects.process(buffer.getChannel(0), buffer.getChannel(1)); } splitter.samples(buffer.getChannel(0), buffer.getChannel(1)); } // write to the line int wrote = buffer.convertToByteArray(bytes, 0, format); line.write(bytes, 0, wrote); } line.drain(); line.stop(); line.close(); line = null; } public int type() { return format.getChannels(); } public void open() { start(); } public void close() { finished = true; } public void addEffect(AudioEffect effect) { effects.add(effect); } public void clearEffects() { effects.clear(); } public void disableEffect(int i) { effects.disable(i); } public void disableEffect(AudioEffect effect) { effects.disable(effect); } public int effectCount() { return effects.size(); } public void effects() { effects.enableAll(); } public void enableEffect(int i) { effects.enable(i); } public void enableEffect(AudioEffect effect) { effects.enable(effect); } public AudioEffect getEffect(int i) { return effects.get(i); } public boolean isEffected() { return effects.hasEnabled(); } public boolean isEnabled(AudioEffect effect) { return effects.isEnabled(effect); } public void noEffects() { effects.disableAll(); } public void removeEffect(AudioEffect effect) { effects.remove(effect); } public AudioEffect removeEffect(int i) { return effects.remove(i); } public void addListener(AudioListener listener) { splitter.addListener(listener); } public int bufferSize() { return splitter.bufferSize(); } public AudioFormat getFormat() { return format; } public void removeListener(AudioListener listener) { splitter.removeListener(listener); } public DataLine getDataLine() { return line; } public float sampleRate() { return splitter.sampleRate(); } public boolean hasEffect(AudioEffect effect) { return effects.contains(effect); } }